﻿using System;
using System.Collections.Generic;
using System.Linq;

namespace Facebook
{
    [Serializable]
    public class CacheablePartialObject<TPropertyKey> : Dictionary<TPropertyKey, Object>
        where TPropertyKey : struct
    {
        public CacheablePartialObject()
            : base(CacheablePartialObject<TPropertyKey>.GetMemberCount())
        { }

        private static Int32 GetMemberCount()
        {
            Type type = typeof(TPropertyKey);
            if (type.IsEnum)
            {
                if (type.GetCustomAttributes(typeof(FlagsAttribute), true).Length == 1) return Enum.GetValues(type).Length;
                else throw new FacebookException("{0} must be decorated with FlagsAttribute to be used as the type for TPropertyKey in CacheablePartialObject.", type.FullName);
            }
            else throw new FacebookException("{0} must be an enum type to be used as the type for TPropertyKey in CacheablePartialObject.", type.FullName);
        }

        protected Object GetValue(TPropertyKey key, Object defaultValue)
        {
            if (this.ContainsKey(key)) return this[key];
            else return defaultValue;
        }

        public Boolean HasProperties(TPropertyKey properties)
        {
            var propertiesValue = Convert.ToInt64(properties);

            return !this.Keys.OfType<Int64>().Any(key => (propertiesValue & key) == 0);
        }

        public Int32 Merge(IDictionary<TPropertyKey, Object> values, Boolean overwrite)
        {
            Int32 addedOrUpdatedCount = 0;
            foreach (var kvp in values)
            {
                if (this.ContainsKey(kvp.Key))
                {
                    if (overwrite)
                    {
                        this[kvp.Key] = kvp.Value;
                        addedOrUpdatedCount++;
                    }
                }
                else
                {
                    this.Add(kvp.Key, kvp.Value);
                    addedOrUpdatedCount++;
                }
            }
            return addedOrUpdatedCount;
        }
    }
}